package com.ep.thirdPlatformProject.system.config.common;

import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.Resource;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.Optional;


@Configuration
@Slf4j
@RequiredArgsConstructor
public class ThreadPoolExecutorConfig {

    @Resource
    ThreadPoolExecutorProperties properties;

    @Bean(name = "executor")
    public ThreadPoolTaskExecutor buildAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 配置核心线程数
        executor.setCorePoolSize(properties.getCorePoolSize());

        // 配置最大线程数
        executor.setMaxPoolSize(properties.getMaxPoolSize());

        //配置队列大小
        executor.setQueueCapacity(properties.getQueueCapacity());

        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(properties.getThreadNamePrefix());

        // 设置线程活跃时间（秒）
        executor.setKeepAliveSeconds(properties.getKeepAliveSeconds());

        // 等待任务在关机时完成--表明等待所有线程执行完
        executor.setWaitForTasksToCompleteOnShutdown(properties.getWaitForTasksToCompleteOnShutdown());

        // rejection-policy：当pool已经达到max size的时候，如何处理新任务
        // CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(properties.getRejectedExecutionHandler());

        // 线程上下文传递
        executor.setTaskDecorator(new ContextDecorator());

        //执行初始化
        executor.initialize();
        return executor;
    }
    static class ContextDecorator implements TaskDecorator {
        @Override
        public @NonNull Runnable decorate(@NonNull Runnable runnable) {
            Optional<RequestAttributes> attrsOpt = Optional.empty();
            try {
                attrsOpt = Optional.of(RequestContextHolder.currentRequestAttributes());
            } catch (Exception e) {
                log.debug("获取 RequestContextHolder 上下文失败：当前线程可能执行的是定时任务!");
            }

            RequestAttributes attrs = attrsOpt.orElse(null);
            return () -> {
                try {
                    if (ObjectUtil.isNotNull(attrs)) {
                        // 将主线程的请求信息，设置到子线程中
                        RequestContextHolder.setRequestAttributes(attrs);
                    }
                    // 执行子线程
                    runnable.run();
                } finally {
                    if (ObjectUtil.isNotNull(attrs)) {
                        RequestContextHolder.resetRequestAttributes();
                    }
                }
            };
        }
    }

}
